
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <sys/time.h>
#include <pthread.h>
#include "BasicRingBuffer.hh"
#include "CryptoPrimitive.hh"
#include "uploading.hh"

#define FINE_NAME_SIZE 32
#define HASH_VALUE_SIZE 32
#define RB_SIZE (1024)
#define SHARE_BUFFER_SIZE (1024)

#define FILE_HEAD (-9)
#define BLOCKCP (-8)
#define BLOCKCP_END (-7)
#define FILE_HF (-10)
using namespace std;

class Encoder {
  public:
      typedef struct{
            int index;    // thread number
            Encoder* obj; // encoder object pointer
        }param_encoder;

    //the file head
        typedef struct {
          unsigned char data[32];
          int filenameSize;
          int filesize;
          int left;
          int numOfblock;
        }fileHead_t;


   //the cipertext of file block
        typedef struct {
         unsigned char* data;
         int cipertextSize;
         int cipertextid;
         unsigned char key[32];
         unsigned char token[HASH_VALUE_SIZE];
         }blockCipertext_t;


         typedef struct {
          unsigned char* data;
          int datasize;
          int blockid;
          unsigned char key[32];
          }fileBlock_t;

          typedef struct{
            union{
              fileBlock_t block;
              fileHead_t file_header;
           };
            int type;
           }fileBlock_Item_t;

           typedef struct {
             char hf[32];
             }fileHF_t;

          typedef struct{
            union{
             blockCipertext_t blockcipertext;
             fileHead_t file_header;
             fileHF_t hfObj;
           };
            int type;
          }blockCipertext_Item_t;

   int n_,m_,r_;
   pthread_t tid_[2];
   RingBuffer<fileBlock_Item_t>* fileblockbuffer_;
   RingBuffer<blockCipertext_Item_t>* blockcipertextbuffer_;
   CryptoPrimitive* cryptoObj_;
   Uploader* uploaderObj_;
   std::string dbDirName_;
   leveldb::DB *db_;
   leveldb::Options dbOptions_;
   leveldb::ReadOptions readOptions_;
   leveldb::WriteOptions writeOptions_;
   leveldb::WriteBatch batch_;

   unsigned char* hfbuffer_;

   Encoder(int n, int m, int r,Uploader* uploaderObj);
  ~Encoder();
   int addFileblock(fileBlock_Item_t item);
   int addBlockCipertext(blockCipertext_Item_t item);
   static void* thread_handler(void* param);
   static void* collect(void* param);
   int storageHf(unsigned char* hfbuffer,char* filename);
   void indicateEnd();
};
